using System;
using NUnit.Framework;
using System.Collections.Generic;
using CommandLineParsing;

namespace ParameteroTests
{
    [TestFixture]
    public class SimpleCommandLineParametersParserTests
    {

        private static Parametero GetParser()
        {
            return new Parametero();
        }

        [Test]
        public void Parse_WhenCalledWithSingleArgument_ShouldBeInListOfValues()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "firstArgument"
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Arguments.Count);
            Assert.AreEqual(args[0], parser.Arguments[0]);
        }


        [Test]
        public void Parse_WhenCalledWithSingleArgumentWithSingleQuotes_ShouldBeInListOfValues()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "'firstArgument'"
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Arguments.Count);
            Assert.AreEqual(args[0], parser.Arguments[0]);
        }

        [Test]
        public void Parse_WhenCalledWithSingleArgumentWithDoubleQuotes_ShouldBeInListOfValues()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               @"""firstArgument"""
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Arguments.Count);
            Assert.AreEqual(args[0], parser.Arguments[0]);
        }


        [Test]
        public void Parse_WhenCalledWithTwoValues_ShouldHaveThemInListOfValuesInSameOrder()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "firstArgument",
                               "secondArgument"
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(2, parser.Arguments.Count);
            Assert.AreEqual(args[0], parser.Arguments[0]);
            Assert.AreEqual(args[1], parser.Arguments[1]);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithMinusWithoutValue_ShouldHaveItInListOfParameters()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "-param1",
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual("param1", parser.Parameters[0].Name);
        }

        [Test]
        public void Parse_WhenCalledWithTwoParametersWithMinusWithoutValue_ShouldHaveThemInListOfParameters()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "-param1",
                               "-param2",
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(2, parser.Parameters.Count);
            Assert.AreEqual("param1", parser.Parameters[0].Name);
            Assert.AreEqual("param2", parser.Parameters[1].Name);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithSlashWithoutValue_ShouldHaveItInListOfParameters()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "/param1",
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual("param1", parser.Parameters[0].Name);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithDoubleMinusWithoutValue_ShouldHaveItInListOfParameters()
        {
            var parser = GetParser();
            var args = new List<string>()
                           {
                               "--param1",
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual("param1", parser.Parameters[0].Name);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithValue_ShouldHaveItInListOfParametersAndValueShouldBeCorrect()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = "someValue";

            var args = new List<string>()
                           {
                               string.Format("--{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual(paramName, parser.Parameters[0].Name);
            Assert.AreEqual(paramValue, parser.Parameters[0].Value);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithValue_ShouldHaveItInListOfParametersAndAllInformationAboutParameterShouldBeCorrect()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = "someValue";
            var wholeParamText = string.Format("--{0}={1}", paramName, paramValue);

            var args = new List<string>()
                           {
                               wholeParamText
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual(paramName, parser.Parameters[0].Name);
            Assert.AreEqual("--", parser.Parameters[0].Prefix);
            Assert.AreEqual(paramValue, parser.Parameters[0].Value);
            Assert.AreEqual("=", parser.Parameters[0].ValueSymbol);
            Assert.AreEqual(wholeParamText, parser.Parameters[0].OriginalParameterText);
        }

        [Test]
        public void Parse_WhenCalledWithSingleParameterWithValueThatHasSingleQuotedText_ShouldHaveItInListOfParametersAndValueShouldBeCorrect()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"'some quoted text'";

            var args = new List<string>()
                           {
                               string.Format("--{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual(paramName, parser.Parameters[0].Name);
            Assert.AreEqual(paramValue, parser.Parameters[0].Value);
        }


        [Test]
        public void Parse_WhenCalledWithSingleParameterWithValueThatHasDoubleQuotedText_ShouldHaveItInListOfParametersAndValueShouldBeCorrect()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("--{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());

            Assert.AreEqual(1, parser.Parameters.Count);
            Assert.AreEqual(paramName, parser.Parameters[0].Name);
            Assert.AreEqual(paramValue, parser.Parameters[0].Value);
        }


        [Test]
        public void GetParameterValue_WhenParameterIsSet_ShouldReturnItsValue()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("/{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());
            var retrievedParamValue = parser.GetParameterValue(paramName);

            Assert.AreEqual(paramValue, retrievedParamValue);
        }


        [Test]
        public void ParameterIsSet_WhenParameterIsSet_ShouldReturnTrue()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("/{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet(paramName);

            Assert.AreEqual(true, result);
        }

        [Test]
        public void ParameterIsSet_WhenParameterIsNotSet_ShouldReturnFalse()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("/{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet("b");

            Assert.AreEqual(false, result);
        }

        [Test]
        [ExpectedException(typeof(Exception))]
        public void GetParameterValue_WhenParameterIsNotSet_ShouldThrowException()
        {
            var parser = GetParser();
            var paramName = "param";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("/{0}={1}", paramName, paramValue)
                           };

            parser.Parse(args.ToArray());
            parser.GetParameterValue("a");
        }

        [Test]
        public void ParameterIsSet_WhenParameterIsSet_ThenItShouldBeSetForEachOfParameterSynonymsAlso()
        {
            var parser = GetParser();
            var paramName = "paramA";
            var synonymOneName = "pa";
            var synonymTwoName = "prma";
            var paramValue = @"""some quoted text""";

            var args = new List<string>()
                           {
                               string.Format("/{0}={1}", paramName, paramValue)
                           };

            parser.Settings.Synonyms.Add(new ParameterSynonym()
                                             {
                                                 Name = "paramA Synonyms",
                                                 SynonymNames = new List<string>()
                                                                {
                                                                    {paramName},
                                                                    {synonymOneName},
                                                                    {synonymTwoName}
                                                                }
                                             });
            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet(paramName);
            var resultForFirstSynonym = parser.ParameterIsSet(synonymOneName);
            var resultForSecondSynonym  = parser.ParameterIsSet(synonymTwoName);

            Assert.AreEqual(true, result);
            Assert.AreEqual(true, resultForFirstSynonym);
            Assert.AreEqual(true, resultForSecondSynonym);
        }

        [Test]
        public void ParameterIsSet_WhenParameterIsNotSet_ShouldReturnFalseForEachOfTheSynonymsAlso()
        {
            var parser = GetParser();
            var paramName = "paramA";
            var synonymOneName = "pa";
            var synonymTwoName = "prma";

            var args = new List<string>()
                           {
                           };

            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet(paramName);
            var resultForFirstSynonym = parser.ParameterIsSet(synonymOneName);
            var resultForSecondSynonym = parser.ParameterIsSet(synonymTwoName);

            Assert.AreEqual(false, result);
            Assert.AreEqual(false, resultForFirstSynonym);
            Assert.AreEqual(false, resultForSecondSynonym);

        }

        [Test]
        public void ParameterIsSet_WhenUsingQuestionmarkForParameterSynonymButItsNotDefined_ShouldReturnFalseIfNotSet()
        {
            var parser = GetParser();
            parser.Settings.Synonyms.Add(new ParameterSynonym()
                                             {
                                                 Name = "help",
                                                 SynonymNames = new List<string>()
                                                                    {
                                                                        {"?"},
                                                                        {"h"},
                                                                        {"hlp"},
                                                                        {"help"}
                                                                    }
                                             });

            parser.Settings.Synonyms.Add(new ParameterSynonym()
            {
                Name = "cleanup",
                SynonymNames = new List<string>()
                                                                    {
                                                               {"cleanup"},
                                                               {"cleanupmode"},
                                                               {"cnp"}
                                                                    }
            });


            var args = new List<string>()
            {
                @"""D:\tmp\b\Shell.ClientApplicationLogicTest.xap""",
                "-cleanup:off"
            };

            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet("?");

            Assert.AreEqual(false, result);
        }

        [Test]
        public void ParameterIsSet_WhenUsingQuestionmarkForParameterSynonymAndItsDefinedInParams_ShouldReturnTrueForQuestionMark()
        {
            var parser = GetParser();
            parser.Settings.Synonyms.Add(new ParameterSynonym()
            {
                Name = "help",
                SynonymNames = new List<string>()
                                                                    {
                                                                        {"?"},
                                                                        {"h"},
                                                                        {"hlp"},
                                                                        {"help"}
                                                                    }
            });

            parser.Settings.Synonyms.Add(new ParameterSynonym()
            {
                Name = "cleanup",
                SynonymNames = new List<string>()
                                                                    {
                                                               {"cleanup"},
                                                               {"cleanupmode"},
                                                               {"cnp"}
                                                                    }
            });


            var args = new List<string>()
            {
                @"""D:\tmp\b\Shell.ClientApplicationLogicTest.xap""",
                "-cleanup:off",
                "-?"
            };

            parser.Parse(args.ToArray());
            var result = parser.ParameterIsSet("?");

            Assert.AreEqual(true, result);
        }


        [Test]
        public void GetParameterValue_IfSetViaSynonym_ShouldReturnItsValueTrueEvenForOtherSynonymName()
        {
            var parser = GetParser();
            parser.Settings.Synonyms.Add(new ParameterSynonym()
            {
                Name = "help",
                SynonymNames = new List<string>()
                                                                    {
                                                                        {"?"},
                                                                        {"h"},
                                                                        {"hlp"},
                                                                        {"help"}
                                                                    }
            });

            parser.Settings.Synonyms.Add(new ParameterSynonym()
            {
                Name = "cleanup",
                SynonymNames = new List<string>()
                                                                    {
                                                               {"cleanup"},
                                                               {"cleanupmode"},
                                                               {"cnp"}
                                                                    }
            });


            var args = new List<string>()
            {
                @"""D:\tmp\b\Shell.ClientApplicationLogicTest.xap""",
                "-cleanup:off",
                "-?"
            };

            parser.Parse(args.ToArray());
            var value = parser.GetParameterValue("cnp");

            Assert.AreEqual("off", value);
        }

    }
}